#include "stdafx.h"
#include "Cashdrawer.h"
using namespace Utility::LoggerLib;
CCashdrawer::CCashdrawer(int nType, int nPort, int nMBType)
    : m_nType(nType),
    m_nPort(nPort),
    m_nMBType(nMBType),
    m_nError(0)
{
    m_ComInfo.hCom = NULL;
    m_ComInfo.nParity = 2;
    m_ComInfo.oWrite.hEvent = NULL;
    m_ComInfo.oRead.hEvent = NULL;
}

BOOL CCashdrawer::Initialize()
{
    return TRUE;
}

//////////////////////////////////////////////////////////////////////////
// CComCashdrawer
#include "ComDefinition.h"
CComCashdrawer::CComCashdrawer(int nPort)
    : CCashdrawer(EComCashdrawer, nPort)
{
}

CComCashdrawer::~CComCashdrawer()
{
    if (NULL != m_ComInfo.hCom)
    {
        PR_CloseCom(m_ComInfo.hCom, m_ComInfo.oWrite, m_ComInfo.oRead);
    }
}

BOOL CComCashdrawer::Initialize()
{
    CCashdrawer::Initialize();

    m_ComInfo.hCom = PR_OpenCom(m_nPort, m_ComInfo.oWrite, m_ComInfo.oRead, m_ComInfo.nParity, m_nError);
    return NULL == m_ComInfo.hCom ? FALSE : TRUE;
}

#define COMMAND_OPEN_COMCASHDRAWER                               _T("\x1b\x70\x00\x50\x10")
#define COMMAND_OPEN_COMCASHDRAWER_LENGTH                  5*sizeof(TCHAR)
#define COMMAND_GET_COMCASHDRAWER_STATUS                      "\x1d\x72\x02"
#define COMMAND_GET_COMCASHDRAWER_STATUS_LENGTH        3
int CComCashdrawer::Open()
{
    return PR_SendStr2Com(m_ComInfo.hCom, _T("\x1b\x70\x00\x50\x10"), 5*sizeof(TCHAR), m_ComInfo.oWrite) ? 0:-1;
}

int CComCashdrawer::GetStatus()
{
    if (!PR_SendStr2LPT(m_ComInfo.hCom, COMMAND_GET_COMCASHDRAWER_STATUS, COMMAND_GET_COMCASHDRAWER_STATUS_LENGTH, m_ComInfo.oRead))
    {
        return CD_STATUS_UNKNOWN;
    }

    TCHAR buf[4];
    memset(buf, '\0', 4*sizeof(TCHAR));
    Sleep(50);
    PR_ReadStrFromCom(m_ComInfo.hCom, buf, 1*sizeof(TCHAR), m_ComInfo.oRead);

    return (buf[0] & 0x01) ? CD_STATUS_CLOSE : CD_STATUS_OPEN;
}

//////////////////////////////////////////////////////////////////////////
// CPTCashdrawer
CPTCashdrawer::CPTCashdrawer(int nPort)
    : CCashdrawer(EPrinterwithCashdrawer, nPort)
{
    if (nPort >= COM1 && nPort <= COM6)
    {
        m_ePort = ECOM;
    }
    else if (nPort >= LPT1 && nPort <= LPT3)
    {
        m_ePort = ELPT;
    }
    else if (nPort >= USB1 && nPort <= USB4)
    {
        m_ePort = EUSB;
    }
    else
        m_ePort = EUnkown;

    Log(DEBUG_LEVEL, EPOSChecker, _T("Create PTCashdrawer, and printer port id is %d, port type is %d."), nPort, m_ePort);
}

CPTCashdrawer::~CPTCashdrawer()
{
    if (NULL != m_ComInfo.hCom)
    {
        switch (m_ePort)
        {
        case ECOM:
            PR_CloseCom(m_ComInfo.hCom, m_ComInfo.oWrite, m_ComInfo.oRead);
            break;

        case  ELPT:
            PR_CloseLPT(m_ComInfo.hCom, m_ComInfo.oWrite, m_ComInfo.oRead);
            break;

        case  EUSB:
        default:
            break;    
        }
    }
}

BOOL CPTCashdrawer::Initialize()
{
    CCashdrawer::Initialize();
    switch (m_ePort)
    {
    case ECOM:
        m_ComInfo.hCom = PR_OpenCom(m_nPort, m_ComInfo.oWrite, m_ComInfo.oRead, m_ComInfo.nParity, m_nError);
        Log(DEBUG_LEVEL, EPOSChecker,  _T("Open COM%d."), m_nPort);
        break;

    case  ELPT:
        m_ComInfo.hCom = PR_OpenLPT(m_nPort-COM6, m_ComInfo.oWrite, m_ComInfo.oRead, m_nError);
        Log(DEBUG_LEVEL, EPOSChecker, _T("Open LPT%d"), m_nPort - COM6);
        break;

    case  EUSB:
    default:
        return FALSE;
        break;    
    }

    return NULL == m_ComInfo.hCom ? FALSE : TRUE;
}

int CPTCashdrawer::Open()
{
    char buf[32] = "\x1b\x70\x00\x50\x10";

    int nRet = -1;
    switch (m_ePort)
    {
    case ECOM:
        nRet = PR_SendStr2Com(m_ComInfo.hCom, buf, 5, m_ComInfo.oWrite);
        break;
    case ELPT:
        nRet = PR_SendStr2LPT(m_ComInfo.hCom, buf, 5, m_ComInfo.oWrite);
        break;
    case EUSB:
    default:
        break;
    }
    Log(DEBUG_LEVEL, EPOSChecker, _T("Open cashdrawer, port id is %d, and return value is %d."), m_nPort, nRet);
    return nRet;
}

int CPTCashdrawer::GetStatus()
{
    char buf[4] = COMMAND_GET_COMCASHDRAWER_STATUS;

    switch (m_ePort)
    {
    case ECOM:
        if (!PR_SendStr2Com(m_ComInfo.hCom, COMMAND_GET_COMCASHDRAWER_STATUS, COMMAND_GET_COMCASHDRAWER_STATUS_LENGTH, m_ComInfo.oRead))
        {
            return CD_STATUS_UNKNOWN;
        }
        break;
    case  ELPT:
        if (!PR_SendStr2LPT(m_ComInfo.hCom, COMMAND_GET_COMCASHDRAWER_STATUS, COMMAND_GET_COMCASHDRAWER_STATUS_LENGTH, m_ComInfo.oRead))
        {
            return CD_STATUS_UNKNOWN;
        }
        break;
    case  EUSB:
    default:
        break;
    }

    memset(buf, '\0', 4);
    Sleep(50);
    switch (m_ePort)
    {
    case ECOM:
        PR_ReadStrFromCom(m_ComInfo.hCom, buf, 1, m_ComInfo.oRead);
        break;
    case  ELPT:
        PR_ReadStrFromLPT(m_ComInfo.hCom, buf, 1, m_ComInfo.oRead);
        break;
    case  EUSB:
    default:
        break;
    }
    int nStatus = (buf[0] & 0x01) ? CD_STATUS_CLOSE : CD_STATUS_OPEN;

    Log(DEBUG_LEVEL, EPOSChecker, _T("Get cashdrawer status, port id is %d, and status is %d."), m_nPort, nStatus);
    return nStatus;

}

///////////////////////////////////////////////////////////////////////
// CMBCashdrawer
#include "MyPortTalk.h"
const static int D525_BASE_ADDRESS = 0x1180;

CMBCashdrawer::CMBCashdrawer(int nMBType)
    : CCashdrawer(EMBCashdrawer, EUnkownPort, nMBType)
{
    m_nStatus = 1;
    m_hFkLib = NULL;
}

CMBCashdrawer::~CMBCashdrawer()
{
    ClosePortTalk();
}

BOOL CMBCashdrawer::Initialize()
{
    Log(DEBUG_LEVEL, EPOSChecker, _T("Mainboard with cashdrawer initialized."));
    if(IsWinNT())
    {
        Log(DEBUG_LEVEL, EPOSChecker, _T("The platform is WinNT"));
        if(!OpenPortTalk())
        {
            Log(ERROR_LEVEL, EPOSChecker, _T("Failed to open port talk, please check the driver."));
            return FALSE;
        }
        Log(DEBUG_LEVEL, EPOSChecker, _T("Success Open PortTalk!"));
    }
    else
    {
        Log(ERROR_LEVEL, EPOSChecker, _T("The OS is not WinNT, not support now."));
        return FALSE;
    }

    switch(m_nMBType)
    {
    case D525:
        return D525_Initialize();
        break;

    case N2600:
        return N2600_Initialize();
        break;

    case N2600JF:
    default:
        break;
    }

    return TRUE;
}

int CMBCashdrawer::Open()
{
    switch(m_nMBType)
    {
    case D525:
        return D525_Open();
        break;
    case N2600:
        return N2600_Open();
        break;
    default:
        break;
    }

    return 1;
}

int CMBCashdrawer::GetStatus()
{
    switch(m_nMBType)
    {
    case D525:
        return D525_GetStatus();
        break;

    case N2600:
        return N2600_GetStatus();
        break;

    default:
        break;
    }

    return -1;

}

BOOL CMBCashdrawer::D525_Initialize()
{
    /*
    byte by = inportb(BASE_M7062 + 0x01);

    by = by | 0x60;				//bit5,bit6
    outportb( BASE_M7062 + 0x01, by);

    by = inportb(BASE_M7062 + 0x05);

    by = by | 0x20;  //bit 5 input
    by = by & 0xBF;  //bit 6 output  

    outportb( BASE_M7062 + 0x05, by);
    */


    Log(DEBUG_LEVEL, EPOSChecker, _T("D525 cashdrawer initialize start."));
    UCHAR  bt = Inp(D525_BASE_ADDRESS + 0x01);
    bt |= 0x60;
    Outp(D525_BASE_ADDRESS + 0x01, bt);
    bt = Inp(D525_BASE_ADDRESS + 0x05);
    bt |= 0x20;
    bt &= 0xBF;

    Outp(D525_BASE_ADDRESS + 0x05, bt);
    Log(DEBUG_LEVEL, EPOSChecker, _T("D525 initialized."));

    return TRUE;
}

int CMBCashdrawer::D525_Open()
{
    /*
    byte by = inportb(BASE_M7062 + 0x0D);

    by = by & 0xBF;
    outportb( BASE_M7062 + 0x0D, by);	//bit6

    Sleep(200);
    by = inportb(BASE_M7062 + 0x0D);
    by = by | 0x40;

    outportb( BASE_M7062 + 0x0D, by);
    */

    Log(DEBUG_LEVEL, EPOSChecker, _T("Open cashdrawer."));
    BYTE bt = Inp(D525_BASE_ADDRESS + 0x0D);
    bt &= 0xBF;
    Outp(D525_BASE_ADDRESS + 0x0D, bt);

    Sleep(200);
    bt = Inp(D525_BASE_ADDRESS + 0x0D);
    bt |= 0x40;

    Outp(D525_BASE_ADDRESS + 0x0D, bt);

    return 0;
}

int CMBCashdrawer::D525_GetStatus()
{
    /*
    byte by = inportb(BASE_M7062 + 0x0D);   //bit 5
    if( by & 0x20 )
    iRes = 1;
    else iRes = 0;
    return iRes;
    */
    BYTE bt = Inp(D525_BASE_ADDRESS + 0x0D);;

    if(bt & 0x20)
    {
        m_nStatus = 1;
    }
    else
    {
        m_nStatus = 0;
    }
    Log(DEBUG_LEVEL, EPOSChecker, _T("Get Cashdrawer status : %d."), m_nStatus);
    return m_nStatus;
}

BOOL CMBCashdrawer::N2600_Initialize()
{

    return TRUE;
}

int CMBCashdrawer::N2600_Open()
{
    Log(DEBUG_LEVEL, EPOSChecker, _T("Open cashdrawer of N2600 mainboard."));
    /*
    zhwang: to do
    open operation logic
    */

    return 0;
}

int CMBCashdrawer::N2600_GetStatus()
{
    /*
    zhwang: to do
    Get status logic
    update current status
    */

    Log(DEBUG_LEVEL, EPOSChecker, _T("Get Cashdrawer status(N2600): %d"), m_nStatus);
    return m_nStatus;
}

////////////////////////////////////////////////////////////////
// CMBCashdrawer_N2600
CMBCashdrawer_N2600::CMBCashdrawer_N2600()
    : CCashdrawer(EMBCashdrawer, EUnkownPort, N2600JF)
{
    m_hFkLib = NULL;
    GPIO_R_PROC = NULL;
    GPIO_W_PROC = NULL;

    m_nStatus = 1;
}

CMBCashdrawer_N2600::~CMBCashdrawer_N2600()
{
    if(NULL != m_hFkLib)
    {
        FreeLibrary(m_hFkLib);
    }
}

BOOL CMBCashdrawer_N2600::Initialize()
{
    Log(DEBUG_LEVEL, EPOSChecker, _T("N2600 cashdrawer initialize start."));
    /*
    zhwang: to do
    initialize logic

    Load fintek.dll
    */


    // Fintek.dll
    m_hFkLib = LoadLibrary(L"Fintek.dll");
    //LoadLibrary("Fintek.dll");
    if(NULL == m_hFkLib)
    {
        // MessageBox(L"Fail to load the the third dll!", L"Error", MB_ICONERROR|MB_OK);
        DWORD dCode = GetLastError();
        Log(ERROR_LEVEL, EPOSChecker, _T("N2600 cashdrawer initialized fail: failed to load Fintek.dll, the error code is %d.!"), dCode);
        return FALSE;
    }

    GPIO_R_PROC = (GETINT2PROC) GetProcAddress(m_hFkLib, "GPIO_LPC_R");
    if(NULL == GPIO_R_PROC)
    {
        Log(ERROR_LEVEL, EPOSChecker, _T("N2600 cashdrawer initialized fail: failed to get gpio_lpc_r interface!"));
        return FALSE;
    }

    GPIO_W_PROC = (SETINT2PROC)(GetProcAddress(m_hFkLib, "GPIO_LPC_W"));
    if(NULL == GPIO_W_PROC)
    {
        Log(ERROR_LEVEL, EPOSChecker, _T("N2600 cashdrawer initialized fail: failed to get gpio_lpc_r interface!"));
        return FALSE;
    }

    Log(DEBUG_LEVEL, EPOSChecker, _T("Success to initialize N2600 mainboard."));
    return TRUE;
}

const static unsigned int GPIO_0_EB_PORT = 0xF0;
const static unsigned int GPIO_0_DATA_PORT = 0xF1;
int CMBCashdrawer_N2600::Open()
{
    Log(DEBUG_LEVEL, EPOSChecker, _T("Invoke Open method."));

    // Must enable output mode first.
    int nOEFlag = GetGPIOVal(0xF0);
    Log(DEBUG_LEVEL, EPOSChecker, _T("GPIO1 current out enable mode is %d."), nOEFlag);
    nOEFlag = nOEFlag| 0x01;

    if(FALSE == SetGPIOVal(0xF0, nOEFlag))
    {
        Log(ERROR_LEVEL, EPOSChecker, _T("Failed to set output mode !"));
        return 1;
    }

    Sleep(50);

    int nVal = GetGPIOVal(0xF1);
    Log(DEBUG_LEVEL, EPOSChecker, _T("GPIO1 current status is %d."), nVal);

    nVal &= 0xFE;
    SetGPIOVal(0xF1, nVal);

    //To do: zhwang
    Sleep(50);
    nOEFlag &= 0xFE;
    if(FALSE == SetGPIOVal(0xF0, nOEFlag))
    {
        Log(ERROR_LEVEL, EPOSChecker, _T("Failed to set output mode !"));
        return 1;
    }
    return 0;
}

int CMBCashdrawer_N2600::GetStatus()
{
    m_nStatus = GetGPIOVal(0xF2);
    Log(DEBUG_LEVEL, EPOSChecker, _T("GPIO2 pin current status is %d."), m_nStatus);

    m_nStatus = (m_nStatus >> 1) & 0x01;
    return m_nStatus;
}

int CMBCashdrawer_N2600::GetGPIOVal(int nPort)
{
    int nData = -1;
    if(NULL != GPIO_R_PROC)
    {
        if(!(*GPIO_R_PROC)(nPort, &nData))
        {
            Log(ERROR_LEVEL, EPOSChecker, _T("N2600 failed to get GPIO value! Port index is %d."), nPort);
        }
    }
    return nData;
}

BOOL CMBCashdrawer_N2600::SetGPIOVal(int nPort, int nVal)
{
    Log(DEBUG_LEVEL, EPOSChecker, _T("Set gpio val, nPort is %d, and value is %d"), nPort, nVal);
    if(NULL != GPIO_W_PROC)
    {
        if(!((*GPIO_W_PROC)(nPort, nVal)))
        {
            Log(ERROR_LEVEL, EPOSChecker, _T("N2600 failed to invoke gpio_lpc_w function! Port index is %d."), nPort);
            return FALSE;
        }
    }

    return TRUE;
}

//////////////////////////////////////////////////////////////////////////
// CMBCashdrawer_N2600_JF
#include "WinIo.h"

CMBCashdrawer_N2600_JF::CMBCashdrawer_N2600_JF(int nPIN)
    : CCashdrawer(EMBCashdrawer, EUnkownPort, N2600JF)
{
    m_hIOLib = NULL;

    GPIO_INIT_PROC = NULL;
    GPIO_SHOWDOWN_PROC = NULL;
    GPIO_SETVAL_PROC = NULL;
    GPIO_GETVAL_PROC = NULL;

    m_nStatus = 1;

    m_bInit = false;
    m_wIAddress = 0;
    m_wOAddress = 0;

    m_nPIN = nPIN;
}

CMBCashdrawer_N2600_JF::CMBCashdrawer_N2600_JF()
    : CCashdrawer(EMBCashdrawer, EUnkownPort, N2600JF)
{

}

CMBCashdrawer_N2600_JF::~CMBCashdrawer_N2600_JF()
{
    ShutdownWinIo();
    if(NULL != m_hIOLib)
    {
        FreeLibrary(m_hIOLib);
    }
};


BOOL CMBCashdrawer_N2600_JF::Initialize()
{
    Log(DEBUG_LEVEL, EPOSChecker, _T("JF-N2600 cashdrawer initialize start."));

    if (!InitializeWinIo())
    {
        Log(ERROR_LEVEL, EPOSChecker, _T("False to invoke InitializeWinIo interface."));

        return FALSE;
    }

    DWORD dwFlag = 0;
    if (0 == m_nPIN)  // 40PIN
    {
        if (!GetPortVal(0x500, &dwFlag, 4))
        {
            Log(ERROR_LEVEL, EPOSChecker, _T("False to get gpio 0x500 value."));
        }
        Log(DEBUG_LEVEL, EPOSChecker, _T("the value of  GPIO8 is %x!"),dwFlag );

        dwFlag |=0x180; // 1 1000 0000 enable bit7 and bit8
        if (!SetPortVal(0x500, dwFlag,2))
        {
            Log(ERROR_LEVEL, EPOSChecker, _T("Failed to set GPIO8, address is 0x500!") );

            return FALSE;
        }

        Log(DEBUG_LEVEL, EPOSChecker, _T("Enable GPIO 8 and GPIO 7,  set to %x."), dwFlag); 
        Sleep(50);

        dwFlag = 0;
        if (!GetPortVal(0x504, &dwFlag, 4))
        {
            Log(ERROR_LEVEL, EPOSChecker, _T("False to get gpio 0x504 value."));
        }
        Log(DEBUG_LEVEL, EPOSChecker, _T("the value of 0x504 is %x."), dwFlag);


        dwFlag &= 0xFEFF;
        dwFlag |= 0x80;
        if (!SetPortVal(0x504, dwFlag, 4))
        {
            Log(ERROR_LEVEL, EPOSChecker, _T("Failed to set GPIO8 output mode, GPIO 7 input mode,  address is 0x504 !") );
            return FALSE;
        }
    }
    else if(1 == m_nPIN) // 60PIN
    {
        if (!GetPortVal(0x500, &dwFlag, 4))
        {
            Log(ERROR_LEVEL, EPOSChecker, _T("False to get gpio 0x500 value."));
        }

        Log(DEBUG_LEVEL, EPOSChecker, _T("Current value of  0x500 is %x!"),dwFlag );

        dwFlag |=0x240; // 0010 0100 0000 enable bit6 and bit 9
        if (!SetPortVal(0x500, dwFlag,2))
        {
            Log(ERROR_LEVEL, EPOSChecker, _T("Failed to enable GPIO6 and GPIO9, address is 0x500!") );

            return FALSE;
        }

        Log(DEBUG_LEVEL, EPOSChecker, _T("Enable GPIO 9 and GPIO 6,  set to %x."), dwFlag); 

        Sleep(50);

        dwFlag = 0;
        if (!GetPortVal(0x504, &dwFlag, 4))
        {
            Log(ERROR_LEVEL, EPOSChecker, _T("False to get gpio 0x504 value."));
        }
        Log(DEBUG_LEVEL, EPOSChecker, _T("the value of 0x504 is %x."), dwFlag);


        // gpio9(bit 9) output mode, gpio6(bit6) input mode  xxxx xx0x x1xx xxxx
        dwFlag &= 0xFDFF;
        dwFlag |= 0x64;
        if (!SetPortVal(0x504, dwFlag, 4))
        {
            Log(ERROR_LEVEL, EPOSChecker, _T("Failed to set GPIO9 output mode, GPIO 6 input mode,  address is 0x504 !") );
            return FALSE;
        }
    }
    else
    {
        Log(ERROR_LEVEL, EPOSChecker, _T("Current PIN setting if false: %d."), m_nPIN);
        return FALSE;
    }

    m_bInit = true;

    Log(DEBUG_LEVEL, EPOSChecker, _T("Set GPIO9 output mode , GPIO 6 input mode, address is 0x504, and value is %x."), dwFlag);

    Log(DEBUG_LEVEL, EPOSChecker, _T("Success to initialize N2600JF mainboard."));


    return TRUE;
}

int CMBCashdrawer_N2600_JF::Open()
{
    Log(DEBUG_LEVEL, EPOSChecker, _T("Invoke Open method."));

    if (!m_bInit)
    {
        Initialize();

    }

    DWORD dwFlag  = 0;

    if (!GetPortVal(0x50C, &dwFlag, 4))
    {
        Log(ERROR_LEVEL, EPOSChecker, _T("Fail to get 0x50c value."));
        return 1;
    }
    Log(INFO_LEVEL, EPOSChecker, _T("Current 0x50C value is %x."), dwFlag);


    if (1 == m_nPIN) // 60PIN
    {
        dwFlag &= 0xFDFF; // xxxx xx0x xxxx xxxx
    }
    else if (0== m_nPIN)  // xxxx xxx0 xxxx xxxx
    {
        dwFlag &= 0xFEFF;
    }
    else
    {
        Log(ERROR_LEVEL, EPOSChecker, _T("Current PIN setting if false: %d."), m_nPIN);
        return 3;
    }

    if (!SetPortVal(0x50C, dwFlag, 4))
    {
        Log(ERROR_LEVEL, EPOSChecker, _T("Fail to open cash drawer (set 0x50c value %x). "), dwFlag);
        return 2;
    }

    Log(INFO_LEVEL, EPOSChecker, _T("Set 0x50C value to be  %x."), dwFlag);
    
    return 0;
}

int CMBCashdrawer_N2600_JF::GetStatus()
{    

    // ZHW: TO DO, need to optimization
    
    if (!m_bInit)
    {
        Initialize();

    }

    DWORD dwFlag = 0;
    if (!GetPortVal(0x50C, &dwFlag, 4))
    {
         Log(ERROR_LEVEL, EPOSChecker, _T("Fail to get 0x50c value."));
         return 1;
    }

    Log(DEBUG_LEVEL, EPOSChecker, _T("Current 0x50C value is %x."), dwFlag);
    
    /*
    DWORD dwStatus = GetGPIOVal(0x50c);
    Log(DEBUG_LEVEL, EPOSChecker, _T("GPIO7 pin current status is %x."), dwStatus);

    m_nStatus = (dwStatus >> 6) & 0x01;    
    */

    DWORD dwOpenFlag = dwFlag;
    DWORD dwStatusFlag = dwFlag;

    m_nStatus = m_nPIN == 1 ? ((dwStatusFlag >> 6) &0x01) :((dwStatusFlag >> 7) &0x01);

    dwOpenFlag = m_nPIN == 1 ? (dwOpenFlag&0x200) : (dwOpenFlag & 0x100);
    //dwOpenFlag &= 0x200;  // xxxx xx0x xxxx xxxx
    unsigned int nBit = m_nPIN == 1? 9: 8;
    if ((dwOpenFlag >> nBit) == 0 && CD_STATUS_OPEN == m_nStatus)
    {

        if (1 == m_nPIN)
        {
            dwFlag |= 0x200;
        }
        else
        {
            dwFlag |= 0x100;
        }
        
        if (!SetPortVal(0x50C, dwFlag, 4))
        {
            Log(ERROR_LEVEL, EPOSChecker, _T("Fail to reset cash drawer (set 0x50c value %x). "), dwFlag);
        }

        Log(DEBUG_LEVEL, EPOSChecker, _T("Reset cash drawer (set 0x50c value %x). "));
    }
 

    return m_nStatus;
}

DWORD CMBCashdrawer_N2600_JF::GetGPIOVal(WORD wIOAddr)
{
    DWORD dwVal = 1;

    if (NULL != GPIO_GETVAL_PROC)
    {
        if (!(*GPIO_GETVAL_PROC)(wIOAddr, &dwVal, 4))
        {
            Log(ERROR_LEVEL, EPOSChecker, _T("Failed to get GPIO value! "));
        }
    }
    return dwVal;
}

BOOL CMBCashdrawer_N2600_JF::SetGPIOVal(WORD wIOAddr, DWORD dwVal)
{
    Log(DEBUG_LEVEL, EPOSChecker, _T("Set GPIO val, Address  is %x, and value is %d"), wIOAddr, dwVal);
    if(NULL != GPIO_SETVAL_PROC)
    {
        if(!(*GPIO_SETVAL_PROC)(wIOAddr, dwVal, 1))
        {
            Log(ERROR_LEVEL, EPOSChecker, _T("Failed to set GPIO %x to %d."), wIOAddr, dwVal);
            return FALSE;
        }
    }

    return TRUE;
}

//////////////////////////////////////////////////////////////////////////
// CMBCashDrawer_JF_GPIO

CMBCashDrawer_JF_GPIO::CMBCashDrawer_JF_GPIO(int nType)
 : CCashdrawer(EMBCashdrawer, EUnkownPort, nType)
{
    m_hIOLib = NULL;
    m_bInit = false;
}

CMBCashDrawer_JF_GPIO::~CMBCashDrawer_JF_GPIO()
{
    ShutdownWinIo();
    if(NULL != m_hIOLib)
    {
        FreeLibrary(m_hIOLib);
    }
}

const static WORD GPIOBASE = 0x500;
BOOL CMBCashDrawer_JF_GPIO::Initialize()
{
    Log(DEBUG_LEVEL, EPOSChecker, _T("JF-mainboard cashdrawer initialize start."));

    if(!InitializeWinIo())
    {
        Log(ERROR_LEVEL, EPOSChecker, _T("False to invoke InitializeWinIo interface."));

        return FALSE;
    }


    DWORD dwFlag = 0;
    WORD wEnableAddrOffset = 0x00;
    WORD wIOFlagOffset = 0x00;


    switch(m_nMBType)
    {
    case JF1037:
    case JFI3:
        wEnableAddrOffset = 0x30;
        wIOFlagOffset = 0x34;
        break;

    default:
        return FALSE;
        break;
    }

    WORD wAddr = GPIOBASE + wEnableAddrOffset;

    // Enable GPIO45 and GPIO46
    if (!GetPortVal(wAddr, &dwFlag, 4))
    {
        Log(ERROR_LEVEL, EPOSChecker, _T("False to get gpio %x value."), wAddr);
    }
    Log(DEBUG_LEVEL, EPOSChecker, _T("the value of  GPIO enable flag is %x!"),dwFlag );

    dwFlag |= 0x6000;
    if (!SetPortVal(wAddr, dwFlag, 2))
    {
        Log(ERROR_LEVEL, EPOSChecker, _T("Failed to set enable register to %x, address is %x!"), dwFlag, wAddr );
        return FALSE;
    }

    Log(DEBUG_LEVEL, EPOSChecker, _T("Enable GPIO mode successfully, registeraddress is %x, and data is %x."), wAddr, dwFlag); 

    Sleep(50);

    // Set Input / output mode
    dwFlag = 0;
    wAddr = GPIOBASE + wIOFlagOffset;
    if (!GetPortVal(wAddr, &dwFlag, 4))
    {
        Log(ERROR_LEVEL, EPOSChecker, _T("False to get gpio I/O mode register data, address is %x."), wAddr);
    }
    Log(DEBUG_LEVEL, EPOSChecker, _T("The data of I/O mode register %x is  %x."), wAddr, dwFlag);
     // gpios45(bit 13) output mode, gpio46(bit14) input mode  x10x xxxx xxxx xxxx
    dwFlag &= 0xdfff;
    dwFlag |= 0x4000;
    if (!SetPortVal(wAddr, dwFlag, 4))
    {
        Log(ERROR_LEVEL, EPOSChecker, _T("Failed to set I/O mode,  address is %x, and value is %x !"), wAddr, dwFlag);
        return FALSE;
    }
    
    m_bInit = true;

    Log(DEBUG_LEVEL, EPOSChecker, _T("Successed to set I/O mode, register address is %x, and value is %x."), wAddr, dwFlag);

    Log(DEBUG_LEVEL, EPOSChecker, _T("Successed to initialize GPIO mainboard."));

    
    return TRUE;
}

int CMBCashDrawer_JF_GPIO::Open()
{
    Log(DEBUG_LEVEL, EPOSChecker, _T("Invoke Open method."));

    if (!m_bInit)
    {
        Initialize();

    }


    WORD wRWOffset = 0x00;
    DWORD dwOpenFlag = 0xFFFF;
    switch(m_nMBType)
    {
    case JF1037:
    case JFI3:
        wRWOffset = 0x38;
        dwOpenFlag = 0xDFFF; // xx0x xxxx xxxx xxxx
        break;

    default:
        return 1;
        break;
    }


    DWORD dwFlag  = 0;
    WORD wAddr = GPIOBASE + wRWOffset;
    if (!GetPortVal(wAddr, &dwFlag, 4))
    {
        Log(ERROR_LEVEL, EPOSChecker, _T("Fail to get i/o register %x data."), wAddr);
        return 2;
    }
    Log(INFO_LEVEL, EPOSChecker, _T("I/O register %x data  is %x."), wAddr, dwFlag);

    dwFlag &=  dwOpenFlag;
    

    if (!SetPortVal(wAddr, dwFlag, 4))
    {
        Log(ERROR_LEVEL, EPOSChecker, _T("Fail to open cash drawer (set register %x to be %x). "), wAddr, dwFlag);
        return 3;
    }

    Log(INFO_LEVEL, EPOSChecker, _T("Open Cashdrawer, Set register %x to  be  %x."), wAddr, dwFlag);

    return 0;
}

int CMBCashDrawer_JF_GPIO::GetStatus()
{

    if (!m_bInit)
    {
        Initialize();

    }

    WORD wRWOffset = 0x00;
    int nStatusBit = 0;
    int nOpenBit = 0;
    switch(m_nMBType)
    {
    case JF1037:
    case JFI3:
        wRWOffset = 0x38;
        nStatusBit = 14;    // xXxx xxxx xxxx xxxx 
        nOpenBit = 13;
        break;

    default:
        return 1;
        break;
    }



    DWORD dwFlag = 0;
    WORD wAddr = GPIOBASE + wRWOffset;

    if (!GetPortVal(wAddr, &dwFlag, 4))
    {
         Log(ERROR_LEVEL, EPOSChecker, _T("Fail to get I/O status register %x data."), wAddr);
         return 1;
    }

    Log(DEBUG_LEVEL, EPOSChecker, _T("Current I/O register %x data is %x."), wAddr, dwFlag);
    

    // Reset Cashdrawer
    DWORD dwOpenFlag = dwFlag;
    DWORD dwStatusFlag = dwFlag;

    m_nStatus = (dwStatusFlag >> nStatusBit) & 0X01;

    dwOpenFlag = dwOpenFlag&0x2000;
   
    if ((dwOpenFlag >> nOpenBit) == 0 && CD_STATUS_OPEN == m_nStatus)
    {
        dwFlag |= 0x2000;
        
        if (!SetPortVal(wAddr, dwFlag, 4))
        {
            Log(ERROR_LEVEL, EPOSChecker, _T("Fail to reset cash drawer (set register %x to be %x). "), wAddr, dwFlag);
        }

        Log(DEBUG_LEVEL, EPOSChecker, _T("Reset cash drawer (set register %x to be %x)."), wAddr, dwFlag);
    }
 

    return m_nStatus;

}